#ifndef GUIENGINE_H_
#define GUIENGINE_H_

#include <string>
#include <SDL/SDL.h>
#include "gui/objects/GUIObject.h"
#include "gui/util/GUIEvent.h"
#include "gui/util/ImageCache.h"
#include "gui/util/ReusableScreenPortion.h"
#include "util/LinkedList.h"

namespace gui {

/*
 * Es el motor que se comunica con SDL, ya sea para la graficacion como para la
 * captura de eventos.
 */
class GUIEngine {
public:
	/* Constructor.*/
	GUIEngine(int width, int height, int bpp, std::string caption,
			bool fullScreen, int deltaX, int deltaY);

	/* Destructor. */
	virtual ~GUIEngine();

	/* Inicializa el motor de la interfaz grafica. */
	// TODO task 33
	//virtual bool start(bool splashScreen);
	virtual bool start(int h, int w, bool splashScreen);

	/* Detiene momentaneamente el motor de la interfaz grafica. */
	virtual void stop();

	/* Dibuja en pantalla los objetos pasados. El parametro clear define si se
	 * escribe sobre lo que ya esta dibujado o si se limpia la pantalla
	 * previamente. */
	virtual void drawGUIObjects(util::LinkedList<GUIObject*>* guiObjects, bool clear);

	/* Limpia la pantalla. */
	virtual void clearScreen();

	/* Reutiliza una porcion de pantalla que ya esta dibujada del ultimo frame. */
	//virtual void reuseScreenPortion(ReusableScreenPortion portion);

	/* Recupera eventos pendientes. */
	virtual int pollEvent(GUIEvent* event);

	/* Espera el siguiente evento. */
	virtual int waitEvent(GUIEvent* event);

	/* Devuelve el estado de la tecla, si esta presionada o no. */
	virtual bool getKeyState(GUIEventKey key);

	/* Redibuja la porcion de pantalla indicada. */
	void drawPortion(Portion portion);

	void setScale(double xScale, double yScale);

private:
	int rColor;
	int gColor;
	int bColor;
	int screenBPP;
	bool fullScreen;
	ImageCache* imageCache;
	std::string screenCaption;

	// Definicion del ancho, alto, y posición actual de la pantalla
	SDL_Rect screenRect;
	// Pantalla vista por el usuario
	SDL_Surface* screen;

	// Desplazamiento de los objetos del mapa e información de la dimensión total del mapa
	SDL_Rect mapRect;

	SDL_Surface* mapSurface;
	double xScale;
	double yScale;

	SDL_Surface* loadImage(std::string fileName, int transparentColorR, int transparentColorG, int transparentColorB);

	Uint32 getPixel(SDL_Surface* surface, int x, int y);

	void putPixel(SDL_Surface* surface, int x, int y, Uint32 pixel);

	SDL_Surface* resize(SDL_Surface* surface, double x, double y);

	SDL_Surface* zoom(SDL_Surface* surface, double z);

	SDL_Surface* rotate180Degrees(SDL_Surface* surface);

	SDL_Surface* rotate90Degrees(SDL_Surface* surface, bool clockwise);

	SDL_Surface* rotateSmallAngle(SDL_Surface* surface, double angle);

	SDL_Surface* fineRotation(SDL_Surface* surface, double angle);

	SDL_Rect getRectFromPortion(Portion portion);

	void refreshScreen();

	SDL_Surface* createSurface(GUIObject* object);

	void drawSurface(SDL_Surface* surface, SDL_Rect* position);

	SDL_Surface* copySurface(SDL_Surface* surface, int h, int w);

	SDL_Surface* createSurface(SDL_Surface* surface, int h, int w);

	void fillSurface(SDL_Surface* surface, int r, int g, int b);

	void fillSurface(SDL_Surface* surface, Uint32 color);

	void lockSurface(SDL_Surface* surface);

	void unlockSurface(SDL_Surface* surface);

	void handleKeyColor(SDL_Surface* originalSurface, SDL_Surface* newSurface);

	void showSplash();

	SDL_Surface* applyScale(SDL_Surface* surface);

	// transforma la dimension del portion segun la escala en la que se muestra la misma
	void resizePortion(Portion* portion);

};

}

#endif
